package controller;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class ControllerTime implements Runnable
{
	public enum TimeState
	{
		NORMAL, NIGHT, MORNING;
	}
	
	private final DateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm");
	
	private Thread _t;
	private Boolean _running;
	private long _time;
	private int _multiplier;
	private TimeState _state;
	
	private static ControllerTime _instance;
	
	private ControllerTime()
	{
		_running = false;
		_time = 0;
		_multiplier = 1;
	}
	
	private void checkTimeState()
	{	
		TimeState newState;
		Date date = new Date(_time);
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		
		if(cal.get(Calendar.HOUR_OF_DAY) >= 0 && cal.get(Calendar.HOUR_OF_DAY) <= 2)
		{
			newState = TimeState.NIGHT;
		}
		else if(cal.get(Calendar.HOUR_OF_DAY) >= 2 && cal.get(Calendar.HOUR_OF_DAY) <= 4)
		{
			newState = TimeState.MORNING;
		}
		else
		{
			newState = TimeState.NORMAL;
		}
		if(newState != _state)
		{
			_state = newState;
			System.out.println("Timestate changed to: " + _state);
		}		
	}
	
	/**
	 * Get the instance of this clock, if it's the first this clock is called it will create the instance first.
	 * (Singleton)
	 * @return An instance of the clock.
	 */
	public static ControllerTime getInstance()
	{
		if(_instance == null)
		{
			_instance = new ControllerTime();
		}
		return _instance;
	}
	
	/**
	 * Sets the time of the clock.
	 * @param time The time to set in String format.(hh:mm)
	 */
	public void setTime(String time)
	{
		int hour = Integer.parseInt(time.split(":")[0]);
		int minutes = Integer.parseInt(time.split(":")[1]);
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.HOUR_OF_DAY, hour);
		cal.set(Calendar.MINUTE, minutes);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		_time = cal.getTimeInMillis();
		checkTimeState();
		System.out.println("Time set: " + DATE_FORMAT.format(new Date(_time)));
	}
	
	/**
	 * Sets the multiplier of the clock which can increase the speed of the clock. (default is 1)
	 * @param multiplier The number at which the speed needs to be increased.
	 */
	public void setMultiplier(int multiplier)
	{
		_multiplier = multiplier;
		System.out.println("Multiplier set: " + _multiplier);
	}
	
	/**
	 * Returns the current time of this clock.
	 * @return The current time as a long.
	 */
	public long getTime()
	{
		return _time;
	}
	
	/**
	 * Return the timestate of this clock (NORMAL, NIGHT, MORNING)
	 * @return The TimeState of this clock.
	 */
	public TimeState getTimeState()
	{
		return _state;
	}
	
	/**
	 * Starts the clock.
	 */
	public void start()
	{
		if(!_running)
		{
			_t = new Thread(this);
			_t.start();
			_running = true;
		}
	}
	
	/**
	 * Stops the clock.
	 */
	public void stop()
	{
		if(_running)
		{
			_running = false;
			try 
			{
				_t.join();
			} 
			catch (InterruptedException e) 
			{
				e.printStackTrace();
			}
		}
	}
	
	@Override
	public void run() 
	{
		long currentTime = System.currentTimeMillis();
		long previousTime = currentTime;
		long elapsedTime = 0;
		
		while(_running)
		{
			previousTime = currentTime;
			currentTime = System.currentTimeMillis();
			elapsedTime += currentTime - previousTime;
			
			if(elapsedTime / 1000f > 1)
			{		
				//One second has passed.
				_time += (_multiplier * 1000);
				//System.out.println("Current time: " + new Date(_time));
				elapsedTime = 0;
				checkTimeState();
			}
			
			try 
			{
				Thread.sleep(10);
			} 
			catch (InterruptedException e) 
			{
				e.printStackTrace();
			}
		}
	}
	
	public int getMultiplier()
	{
		return _multiplier;
	}
}
